package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/9/2 10:39
 * @Version 1.0
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo> implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    /*
    ware:
        url: http://localhost:9001
     */
    //  获取仓库地址
    @Value("${ware.url}")
    private String wareUrl;

    @Override
    public void execExpiredOrder(Long orderId) {

        //  根据订单Id 将订单状态改为 CLOSED.
        //  根据订单Id 将订单状态改为 PAID.
        //  根据订单Id 将订单状态改为 xxx.
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
//        this.updateOrderStatus(orderId,ProcessStatus.PAID);
//        this.updateOrderStatus(orderId,ProcessStatus.DELEVERED);
        //  发送消息给payment-service让其关闭paymentInfo;
        this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
    }

    @Override
    public void sendMsgToWare(Long orderId) {
        //  订单这个状态要更新
        this.updateOrderStatus(orderId,ProcessStatus.NOTIFIED_WARE);
        //  发送的内容由订单+订单明细组成
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //  将订单对象转换为一个map 或JSONObject 对象。
        Map map = this.initWare(orderInfo);
        //  将map 转换json 发送出去
        this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK, JSON.toJSONString(map));
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        //  根据订单Id 将订单状态改为 CLOSED.
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
        if ("2".equals(flag)){
            //  发送消息给payment-service让其关闭paymentInfo;
            this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }
    }

    @Override
    public List<OrderInfo> orderSplit(String orderId, String wareSkuMap) {
        /*
        1.  先获取到原始订单： 要被拆分的订单
        2.  将wareSkuMap 转换为我们能操作的java 对象 [{"wareId":"1","skuIds":["26"]},{"wareId":"2","skuIds":["29","30"]}]
        3.  创建新的子订单并给子订单进行赋值
        4.  将子订单添加到集合中
        5.  包子订单
        6。 修改原始订单状态
         */
        //  声明一个子订单集合
        List<OrderInfo> orderInfoList = new ArrayList<>();
        //  原始订单
        OrderInfo originOrderInfo = this.getOrderInfo(Long.parseLong(orderId));
        //  转换为List<Map>
        List<Map> mapList = JSON.parseArray(wareSkuMap, Map.class);
        //  判断
        if (!CollectionUtils.isEmpty(mapList)){
            //  循环变量
            for (Map map : mapList) {
                //  获取仓库Id
                String wareId = (String) map.get("wareId");
                List<String> skuIdList = (List<String>) map.get("skuIds");
                //  创建一个新的子订单并给子订单赋值
                OrderInfo subOrderInfo = new OrderInfo();
                //  属性拷贝
                BeanUtils.copyProperties(originOrderInfo,subOrderInfo);
                //  设置Id 为null 防止主键冲突
                subOrderInfo.setId(null);
                //  85,Administrator,15099999999,12896.00,CLOSED,2,ONLINE,北京市昌平区宏福科技园,"",ATGUIGU1693981567912741,购买商品,2023-09-06 14:26:08,2023-09-07 14:26:08,CLOSED,,,,,,0.00,12896.00,,,,2023-09-06 06:26:08,2023-09-06 06:28:02,0
                //  86,Administrator,15099999999,12896.00,CLOSED,2,ONLINE,北京市昌平区宏福科技园,"",ATGUIGU1693981567912741,购买商品,2023-09-06 14:26:08,2023-09-07 14:26:08,CLOSED,,,,,,0.00,12896.00,,,,2023-09-06 06:26:08,2023-09-06 06:28:02,0
                subOrderInfo.setParentOrderId(Long.parseLong(orderId));
                //  赋值仓库Id
                subOrderInfo.setWareId(wareId);
                //  计算子订单明细 -- 来自于原始订单明细. originOrderInfo.getOrderDetailList(); 26 29 30
                List<OrderDetail> orderDetailList = originOrderInfo.getOrderDetailList();
                //  [{"wareId":"1","skuIds":["26"]},{"wareId":"2","skuIds":["29","30"]}]
                //  第一次循环 {"wareId":"1","skuIds":["26"]} 第二次循环 {"wareId":"2","skuIds":["29","30"]}
                //  子订单明细集合
                List<OrderDetail> detailList = orderDetailList.stream().filter(orderDetail -> skuIdList.contains(orderDetail.getSkuId().toString())).collect(Collectors.toList());
                subOrderInfo.setOrderDetailList(detailList);
                //  计算子订单金额
                subOrderInfo.sumTotalAmount();
                //  添加子订单到集合
                orderInfoList.add(subOrderInfo);
                //  保存子订单.
                this.saveOrderInfo(subOrderInfo);
            }
        }
        //  修改原始订单状态.
        this.updateOrderStatus(Long.parseLong(orderId),ProcessStatus.SPLIT);
        //  返回子订单集合
        return orderInfoList;
    }

    /**
     * 将订单对象转换为map 集合
     * @param orderInfo
     * @return
     */
    @Override
    public Map initWare(OrderInfo orderInfo) {
        //  创建map 对象
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("orderId",orderInfo.getId());
        hashMap.put("consignee", orderInfo.getConsignee());
        hashMap.put("consigneeTel", orderInfo.getConsigneeTel());
        hashMap.put("orderComment", orderInfo.getOrderComment());
        hashMap.put("orderBody", orderInfo.getTradeBody());
        hashMap.put("deliveryAddress", orderInfo.getDeliveryAddress());
        hashMap.put("paymentWay", "2");
        hashMap.put("wareId", orderInfo.getWareId());

        //  获取到订单明细.
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            List<HashMap<String, Object>> mapList = orderDetailList.stream().map(orderDetail -> {
                //  创建map 对象
                HashMap<String, Object> map = new HashMap<>();
                map.put("skuId",orderDetail.getSkuId());
                map.put("skuNum",orderDetail.getSkuNum());
                map.put("skuName",orderDetail.getSkuName());
                return map;
            }).collect(Collectors.toList());
            hashMap.put("details", mapList);
        }
        return hashMap;
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        //  先获取订单信息
        OrderInfo orderInfo = this.getById(orderId);
        //  判断
        if (null != orderInfo) {
            //  获取到订单明细
            List<OrderDetail> orderDetailList = this.orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderId));
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;
    }

    /**
     * 修改订单状态
     * @param orderId
     * @param processStatus
     */
    @Override
    public void updateOrderStatus(Long orderId, ProcessStatus processStatus) {
        //  取消订单本质：修改订单状态.
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public IPage<OrderInfo> getOrderPageList(Page<OrderInfo> orderInfoPage, String userId, String orderStatus) {
        //  调用mapper方法
        IPage<OrderInfo> infoIPage = orderInfoMapper.selectOrderPageList(orderInfoPage, userId, orderStatus);
        infoIPage.getRecords().forEach(orderInfo -> {
            //  给订单状态名称赋值  UNPAID--->未支付  PAID--支付
            orderInfo.setOrderStatusName(OrderStatus.getStatusNameByStatus(orderInfo.getOrderStatus()));
        });
        return infoIPage;
    }

    @Override
    public Boolean checkStock(Long skuId, Integer skuNum) {
        //  http://localhost:9001/hasStock?skuId=10221&num=2
        String flag = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        //  返回结果
        return "1".equals(flag);
    }

    @Override
    public void delTradeNo(String userId) {
        //  del key
        this.redisTemplate.delete("tradeNo:"+userId);
    }

    /**
     *
     * @param tradeNo 页面传递的
     * @param userId  获取缓存的
     * @return
     */
    @Override
    public Boolean checkTradeNo(String tradeNo, String userId) {
        //  同时将这个流水号存储到缓存.
        String tradeNoKey = "tradeNo:"+userId;
        String redisTradeNo = (String) this.redisTemplate.opsForValue().get(tradeNoKey);
        //  返回比较结果
        return tradeNo.equals(redisTradeNo);
    }

    @Override
    public String getTradeNo(String userId) {
        //  生成流水号
        String tradeNo = UUID.randomUUID().toString();
        //  同时将这个流水号存储到缓存.
        String tradeNoKey = "tradeNo:"+userId;
        //  存储
        this.redisTemplate.opsForValue().set(tradeNoKey,tradeNo);
        return tradeNo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrderInfo(OrderInfo orderInfo) {
        //  order_info order_detail
        // total_amount order_status user_id out_trade_no trade_body operate_time expire_time process_status
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        String outTradeNo = "ATGUIGU"+System.currentTimeMillis()+new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setTradeBody("购买商品");
        orderInfo.setOperateTime(new Date());
        //  过期时间如何处理? 当前系统时间上+1天 ,根商品的库存剩余数量有关系?
        //  Calendar calendar = Calendar.getInstance();
        //  calendar.add(Calendar.DATE,1);
        //  orderInfo.setExpireTime(calendar.getTime());
        //  LocalTime LocalDate LocalDateTime
        //  如何获取到当前系统时间; LocalDateTime.now()
        //  在当前系统时间基础上 +1 天
        LocalDateTime localDateTime = LocalDateTime.now().plusDays(1);
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        /*
        如果是 JDK8 的应用，可以使用 Instant 代替 Date，LocalDateTime 代替 Calendar，DateTimeFormatter 代替
            SimpleDateFormat，官方给出的解释：simple beautiful strong immutable thread-safe。
         */
        orderInfo.setExpireTime(Date.from(zonedDateTime.toInstant()));
        //  订单的进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //  保存订单主信息
        orderInfoMapper.insert(orderInfo);

        //  获取到订单明细
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        //  循环遍历
        if (!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) {
                //  赋值订单Id
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            }
        }

        //  发送一个延迟消息
        this.rabbitService.sendDelayMsg(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,MqConst.ROUTING_ORDER_CANCEL,orderInfo.getId(),MqConst.DELAY_TIME);
        return orderInfo.getId();
    }

    public static void main(String[] args) {
        //  如果是 JDK8 的应用，可以使用 Instant 代替 Date，LocalDateTime 代替 Calendar，DateTimeFormatter 代替
        //  SimpleDateFormat，官方给出的解释：simple beautiful strong immutable thread-safe。
        //  LocalDateTime 代替 Calendar
        //  Calendar calendar = Calendar.getInstance();
        //  calendar.add(Calendar.DATE,1);
        LocalDateTime localDateTime = LocalDateTime.now().plusDays(1);
        //  定义时区
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        //  创建对象 可以使用 Instant 代替 Date
        Date from = Date.from(zonedDateTime.toInstant());
        System.out.println(from);
        //  DateTimeFormatter 代替 SimpleDateFormat
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//        System.out.println(localDateTime.toLocalDate().format(formatter));
        System.out.println(localDateTime.format(formatter));


    }
}
